<?php
/**
 * @see Zend_controller_Action_Helper_Abstract
 */
require_once 'Zend/Controller/Action/Helper/Abstract.php';

/**
 * @see Zend_Loader
 */
require_once 'Zend/Loader.php';


/**
 * Enter description here...
 *
 */
class Impertinent_Controller_Action_Helper_ModelLoader extends Zend_Controller_Action_Helper_Abstract
{
    /**
     * Models base path
     *
     * @var string
     */
    protected $_modelsBasePath = ':moduleDir/models';

    /**
     * Models controller directory path
     *
     * @var string
     */
    protected $_modelsControllerPath = ':controller';

    protected $_delimiters = null;

    /**
     * Construct
     *
     * @param string $modelsBasePath Base path
     */
    public function __construct($modelsBasePath = ':moduleDir/models', $modelsControllerPath = ':controller')
    {
        $this->_modelsBasePath = (string) $modelsBasePath;
        $this->_modelsControllerPath = (string) $modelsControllerPath;
    }

    /**
     * direct(): Perform helper when called as
     * $this->_helper->ModelLoader($model, $module, $controller);
     *
     * @param string $model
     * @param string $module
     * @param string $controller
     * @return Zend_Controller_Action_Helper_ModelLoader
     */
    public function direct($model, $module = null, $controller = null)
    {
        $this->load($model, $module, $controller);
        return $this;
    }

    /**
     * Load a model
     *
     * Load model from different module
     *
     * @param string $model
     * @param string $module
     * @param string $controller
     * @return Zend_Db_Table_Abstract
     */
    public function load($model, $module = null, $controller = null)
    {
        if (class_exists($model)) {
            return;
        }

        $front = Zend_Controller_Front::getInstance();

        $vars = array();
        if ( ! empty($module) || ! empty($controller)) {
            $vars = array(
                'moduleDir' => $front->getControllerDirectory($module),
                'controller' => $controller
            );
        }

        $dirs = array(
            $this->_translateSpec($this->_modelsBasePath, $vars),
            $this->_translateSpec($this->_modelsBasePath . '/' . $this->_modelsControllerPath, $vars)
        );

        Zend_Loader::loadClass($model, $dirs);
        return $this;
    }

    /**
     * Inject values into a spec string
     *
     * Allowed variables are:
     * - :moduleDir - current module directory
     * - :module - current module name
     * - :controller - current controller name
     * - :action - current action name
     * - :suffix - view script file suffix
     *
     * @param  string $spec
     * @param  array $vars
     * @return string
     */
    protected function _translateSpec($spec, array $vars = array())
    {
        $front = Zend_Controller_Front::getInstance();
        $request = $this->getRequest();
        $module    = $request->getModuleName();
        $controller = $request->getControllerName();
        $action    = $request->getActionName();

        // Need to get default module name if null returned, so that we get a
        // controller directory
        if (null === $module) {
            $module = $front->getDispatcher()->getDefaultModule();
        }

        $moduleDir = $front->getControllerDirectory($module);
        if ((null === $moduleDir) || is_array($moduleDir)) {
            throw new Zend_Controller_Action_Exception('ModelLoader cannot locate module directory');
        }

        foreach ($vars as $key => $value) {
            switch ($key) {
                case 'module':
                case 'controller':
                case 'action':
                case 'moduleDir':
                    $$key = (string) $value;
                    break;
                default:
                    break;
            }
        }

        // Module, controller, and action names need normalized delimiters
        if (null === $this->_delimiters) {
            $dispatcher        = $front->getDispatcher();
            $wordDelimiters    = $dispatcher->getWordDelimiter();
            $pathDelimiters    = $dispatcher->getPathDelimiter();
            $this->_delimiters = array_unique(array_merge($wordDelimiters, (array) $pathDelimiters));
        }
        $moduleDir = dirname($moduleDir);

        $replacements = array(
            ':moduleDir' => $moduleDir,
            ':module' => str_replace($this->_delimiters, '-', $module),
            ':controller' => str_replace($this->_delimiters, '-', $controller),
            ':action' => str_replace($this->_delimiters, '-', $action)
        );
        $value = str_replace(array_keys($replacements), array_values($replacements), $spec);
        return $value;
    }

}
